package com.example.spider.config;

import com.example.spider.util.FileBasedCollection;
import com.example.spider.util.FileBasedMap;
import jakarta.annotation.Nonnull;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

@Configuration
@Order(Integer.MIN_VALUE)
public class StorageConfiguration implements ApplicationListener<ContextRefreshedEvent> {

    @Qualifier("proxy_xsdaili_distinct_set")
    @Bean("proxy_xsdaili_distinct_set")
    public FileBasedCollection<ConcurrentSkipListSet<String>, String> autoReloadFileSet(@Value("${spider.proxy.storage.distinctSet.file:${user.home}/spider/ipProxy/allIpPort.txt}") String filePath) {
        return new FileBasedCollection<>(new ConcurrentSkipListSet<>(), new File(filePath));
    }
    
    @Qualifier("tester_ex_info")
    @Bean("tester_ex_info")
    public FileBasedMap<ConcurrentHashMap<String, AtomicInteger>, String, AtomicInteger> tester_ex_info(@Value("${spider.proxy.storage.exRecord.file:${user.home}/spider/ipProxy/testProxyEx.txt}") String filePath) {
        return new FileBasedMap<>(new ConcurrentHashMap<>(), String.class, AtomicInteger.class, new File(filePath));
    }

    @Qualifier("spider_ex_info")
    @Bean("spider_ex_info")
    public FileBasedMap<ConcurrentHashMap<String, AtomicInteger>, String, AtomicInteger> spider_ex_info(@Value("F:/spider/spiderNoRetryEx.txt") String filePath) {
        return new FileBasedMap<>(new ConcurrentHashMap<>(), String.class, AtomicInteger.class, new File(filePath));
    }

    @Qualifier("noRetryUrls")
    @Bean("noRetryUrls")
    public FileBasedCollection<ConcurrentSkipListSet<String>, String> noRetryUrls(@Value("F:/spider/noRetryUrls.txt") String filePath) {
        return new FileBasedCollection<>(new ConcurrentSkipListSet<>(), new File(filePath));
    }

    @Qualifier("test_url_set")
    @Bean("test_url_set")
    public FileBasedCollection<ConcurrentSkipListSet<String>, String> testSpeed(@Value("F:/testSpeed.txt") String filePath) {
        return new FileBasedCollection<>(new ConcurrentSkipListSet<>(), new File(filePath));
    }

    @Qualifier("dropUrls")
    @Bean("dropUrls")
    public FileBasedCollection<ConcurrentSkipListSet<String>, String> dropUrls(@Value("F:/spider/dropUrls.txt") String filePath) {
        return new FileBasedCollection<>(new ConcurrentSkipListSet<>(), new File(filePath));
    }

    @SuppressWarnings("rawtypes")
    @Override
    public void onApplicationEvent(@Nonnull ContextRefreshedEvent event) {
        // 加载文件内容 / 注册定时任务
        ThreadPoolTaskScheduler taskScheduler = event.getApplicationContext().getBean(ThreadPoolTaskScheduler.class);
        Map<String, FileBasedCollection> fileSetMap = event.getApplicationContext().getBeansOfType(FileBasedCollection.class);
        Map<String, FileBasedMap> fileMapMap = event.getApplicationContext().getBeansOfType(FileBasedMap.class);

        Consumer<FileBasedCollection<?, ?>> registerSetScheduleConsumer = s ->
                taskScheduler.schedule(s::syncToPersistenceStorage, s.getSyncToPersistenceStorageTrigger());
        FileBasedCollection.setRegisterConsumer(registerSetScheduleConsumer);
        Consumer<FileBasedMap<?, ?, ?>> registerMapScheduleConsumer = s ->
                taskScheduler.schedule(s::syncToPersistenceStorage, s.getSyncToPersistenceStorageTrigger());
        FileBasedMap.setRegisterConsumer(registerMapScheduleConsumer);

        fileSetMap.entrySet().stream().parallel().map(e -> {
                    // 设置 BeanName
                    e.getValue().setName(e.getKey());
                    return e.getValue();
                })
                // 从文件加载
                .peek(FileBasedCollection::loadFromStorage)
                // 注册定时任务
                .map(o -> (FileBasedCollection<?, ?>) o)
                .forEach(registerSetScheduleConsumer);

        fileMapMap.entrySet().stream().parallel().map(e -> {
                    e.getValue().setName(e.getKey());
                    return e.getValue();
                })
                .peek(FileBasedMap::loadFromStorage)
                .map(o -> (FileBasedMap<?, ?, ?>) o)
                .forEach(registerMapScheduleConsumer);
    }

}
